﻿/*
* Copyright 2010 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using System.Reflection;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Context;
using log4net;

namespace Ngilead.Test.DAO
{
    /// <summary>
    /// Nhibernate context class
    /// </summary>
    public class NhibernateContext
    {
        /// <summary>
        /// Context enumeration
        /// </summary>
        public enum enumContext
        {
            /// <summary>Stateless</summary>
            Stateless,
            /// <summary>Stateful</summary>
            Stateful,
            /// <summary>Legacy</summary>
            Legacy,
            /// <summary>Gwt</summary>
            Gwt,
            /// <summary>Java5</summary>
            Java5,
            /// <summary>Proxy</summary>
            Proxy,
            /// <summary>Annotated</summary>
            Annotated
        };

        #region Private

        private static ILog _log = LogManager.GetLogger(typeof(NhibernateContext));             // Logger	
        private static enumContext _context;                                                    // Current context	
        private static ISessionFactory _sessionFactory;                                         // Current SessionFactory

        #endregion

        // get the appropriate context file associated with the current application configuration	 
        private static String ContextPath
        {
            get
            {
                switch (_context)
                {
                    case enumContext.Stateless:
                    case enumContext.Stateful:
                    case enumContext.Legacy:
                    case enumContext.Gwt:
                    case enumContext.Java5:
                    case enumContext.Proxy:
                    case enumContext.Annotated:
                        return _context.ToString();
                    default:
                        throw new Exception("Invalid context");
                }
            }
        }

        #region ContextFile

        // get the appropriate context file associated with the current application configuration	 
        private static String ContextFile
        {
            get
            {
                return String.Concat(ContextPath, "/hibernate.cfg.xml");
            }
        }

        #endregion

        #region Context

        /// <summary>
        /// Context
        /// </summary>
        public static enumContext Context
        {
            get
            {
                return _context;
            }
            set
            {
                if (_context != value)
                {
                    _context = value;
                    if (_sessionFactory != null)
                        _sessionFactory.Close();
                    _sessionFactory = null;
                }
            }
        }

        #endregion

        #region SessionFactory

        /// <summary>
        /// SessionFactory
        /// </summary>
        /// <returns></returns>
        public static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    try
                    {
                        Configuration configuration = new Configuration();
                        switch (_context)
                        {
                            case enumContext.Java5:
                            case enumContext.Annotated:
                                //_sessionFactory = new AnnotationConfiguration().configure(getContextFile()).buildSessionFactory();
                                throw new NotImplementedException();
                            case enumContext.Stateful:
                            case enumContext.Legacy:
                            case enumContext.Gwt:
                            case enumContext.Proxy:
                                throw new NotImplementedException();
                            case enumContext.Stateless:
                                configuration.Configure(Assembly.GetExecutingAssembly(), String.Format("Ngilead.Test.Resources.{0}.Nhibernate.hibernate.cfg.xml", ContextPath));
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                        new SchemaExport(configuration).Execute(false, true, false);
                        _sessionFactory = configuration.BuildSessionFactory();
                        ISession session = _sessionFactory.OpenSession();
                        CurrentSessionContext.Bind(session);
                        TestHelper.InitializeDB();
                        session.Close();
                    }
                    catch (Exception ex)
                    {
                        _log.Error("Initial SessionFactory creation failed.", ex);
                        throw;
                    }
                }
                return _sessionFactory;
            }
        }

        #endregion

        #region Session
        
        /// <summary>
        /// Return the already opened session or a new one if needed
        /// </summary>
        /// <returns>Session</returns>
        public static ISession GetSession()
        {
            ISession session = GetCurrentSession();
            if (session == null)
            {
                if (_log.IsDebugEnabled)
                    _log.Debug("No current session, opening a new one");
                session = SessionFactory.OpenSession();
                CurrentSessionContext.Bind(session);
            }
            return session;
        }

        /// <summary>
        /// Return the already opened session (returns null if none is opened)
        /// </summary>
        /// <returns>Session</returns>
        private static ISession GetCurrentSession()
        {
            ISession session = null;
            try
            {
                session = SessionFactory.GetCurrentSession();
                if (session.IsConnected == false)
                {
                    if (_log.IsDebugEnabled)
                        _log.Debug("Session is not connected");
                    session = null;
                }
            }
            catch (HibernateException ex)
            {
                if (_log.IsDebugEnabled)
                    _log.Debug("Exception during GetCurrentSession()", ex);
                session = null;
            }
            return session;
        }

        #endregion

        #region Type

        /// <summary>
        /// Get the appropriate model type associated with the current application configuration
        /// </summary>
        /// <param name="contract"></param>
        /// <returns></returns>
        public static Type GetModelType(Type contract)
        {
            try
            {
                return Type.GetType(String.Format("Ngilead.Test.Models.{0}.{1}, Ngilead.Test.Resources", ContextPath, contract.Name));
            }
            catch (Exception)
            {
                throw new Exception("Unknown contract");
            }
        }

        #endregion
    }
}
